using System;
using UnityEngine.Serialization;

namespace UnityEngine.Rendering.Universal {
    public enum RadialBlurQuality
    {
        RadialBlur_4Tap = 0,
        RadialBlur_6Tap = 1,
        RadialBlur_8Tap = 2,
    }

    [Serializable]
    public sealed class RadialBlurQualityParameter : VolumeParameter<RadialBlurQuality> {
        public RadialBlurQuality m_RadialBlurQuality;
        public RadialBlurQualityParameter(RadialBlurQuality radialBlurQuality, bool overrideState = false) : base(radialBlurQuality, overrideState) {
            this.m_RadialBlurQuality = radialBlurQuality;
        }
    
    }

    [Serializable,VolumeComponentMenu("Post-processing/RadialBlurV2")]
    public class RadialBlurV2 : VolumeComponent, IPostProcessComponent
    {
        public BoolParameter ActiveOn = new BoolParameter(false, true);

        public BoolParameter reverseDir = new BoolParameter(false, true);
        public BoolParameter useDither = new BoolParameter(false, false);
        public BoolParameter blackWithFlash = new BoolParameter(false, false);
        public BoolParameter InvertBlackWrite = new BoolParameter(false, false);
        public ClampedFloatParameter blackWithStep = new ClampedFloatParameter(0.1f,0, 1, false);
        
        public RadialBlurQualityParameter QualityLeve = new RadialBlurQualityParameter(RadialBlurQuality.RadialBlur_4Tap);
        public ClampedFloatParameter blurRadius = new ClampedFloatParameter(0f, 0f, 1f, false);
        public ClampedFloatParameter darkThreshold = new ClampedFloatParameter(0f, 0f, 1f, false);
        public TextureParameter noiseTex = new TextureParameter(null,false);
        public ClampedFloatParameter noiseRadius = new ClampedFloatParameter(0f, 0f, 5f, false);
        public ClampedFloatParameter noiseSpeed = new ClampedFloatParameter(0f, 0f, 2f, false);
        
        public Vector2Parameter blurCenter = new Vector2Parameter(new Vector2(0.5f, 0.5f), false);

        static readonly int m_ParamsId = Shader.PropertyToID("_Params");
        static readonly int m_AdditionParamsId = Shader.PropertyToID("_AdditionParams");
        static readonly int m_DarkThreshold = Shader.PropertyToID("_DarkThreshold");
        static readonly int m_ReversParam = Shader.PropertyToID("_ReverseParam");
        static readonly int m_NoiseTex = Shader.PropertyToID("_RadialNoiseTex");
        
        
        public bool IsActive()
        {
            return active && ActiveOn.value;
        }

        public bool IsTileCompatible()
        {
            return false;
        }
        
        public override void SetActive(bool value)
        {
            base.SetActive(value);
            ActiveOn.overrideState = true;
            ActiveOn.value = value;
        }

        public override void UpdateVector4(float f1, float f2, float f3, float f4, int type = 0)
        {
            blurRadius.overrideState = true;
            blurRadius.value = f1;

            darkThreshold.overrideState = true;
            darkThreshold.value = f2;

            blurCenter.overrideState = true;
            blurCenter.value = new Vector2(f3, f4);

            reverseDir.overrideState = true;
            reverseDir.value = type == 1;
        }

        public override void UpdateVector2(float f1, float f2, int type = 0)
        {
            blurRadius.overrideState = true;
            blurRadius.value = f1;

            darkThreshold.overrideState = true;
            darkThreshold.value = f2;
            
            reverseDir.overrideState = true;
            reverseDir.value = type == 1;
        }

        public override void UpdateCenter(Vector2 centerPoint)
        {
            blurCenter.overrideState = true;
            blurCenter.value = centerPoint;
        }

        public Vector4 additionParamat = new Vector4();

        public bool Render(CommandBuffer cmd, Material material, RTHandle source, RTHandle destination) {
            material.SetVector(m_ParamsId, new Vector4(blurRadius.value * 0.02f, Mathf.Clamp(blurCenter.value.x,0,1), Mathf.Clamp(blurCenter.value.y,0,1), 0.0f));
            material.SetFloat(m_DarkThreshold, (1 - darkThreshold.value));
            float reverseParam = 1;
            if (reverseDir.value)
            {
                reverseParam = -1;
            }
            material.SetFloat(m_ReversParam, reverseParam);

            if (darkThreshold.value > 0 || noiseRadius.value > 0 || blurRadius.value > 0)
            {
                if (CheckVolumeDirty)
                {
                    SetAdditionData(material); 
                    ResetDirty();
                }
                cmd.Blit(source, BlitDstDiscardContend(cmd, destination), material, (int)QualityLeve.value);
                return true;
            }

            return false;
        }

        private void SetAdditionData(Material material)
        {
            int mask = 0;
            mask = SetBlitMaskActive(mask, (int)RadiaMask.UseDither, this.useDither.value);
            mask = SetBlitMaskActive(mask, (int)RadiaMask.BlackWithFlash, this.blackWithFlash.value);
            mask = SetBlitMaskActive(mask, (int)RadiaMask.NoiseTex, this.noiseTex.value!=null); 
            mask = SetBlitMaskActive(mask, (int)RadiaMask.InvertBlackWrite, this.InvertBlackWrite.value); 
            additionParamat.x = mask;
            additionParamat.y = noiseRadius.value;      
            additionParamat.z = blackWithStep.value;
            additionParamat.w = noiseSpeed.value;
            
            material.SetVector(m_AdditionParamsId, additionParamat);
            material.SetTexture(m_NoiseTex,noiseTex.value);
        }
        

        private int SetBlitMaskActive(int maskValue,int bitMask,bool maskActive)
        {
            int mask = 1 << bitMask;
            if (maskActive) maskValue |= mask;
            else maskValue &= ~mask;
            return maskValue;
        }
        private enum RadiaMask 
        {
           UseDither  = 0,
           BlackWithFlash = 1,
           NoiseTex  = 2,
           InvertBlackWrite = 3
        }
    }
}

